/*
 * BEEM is a videoconference application on the Android Platform.
 * Copyright (C) 2009 by Frederic-Charles Barthelery,
 * Jean-Manuel Da Silva,
 * Nikita Kozlov,
 * Philippe Lago,
 * Jean Baptiste Vergely,
 * Vincent Veronis.
 * This file is part of BEEM.
 * BEEM is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * BEEM is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with BEEM. If not, see <http://www.gnu.org/licenses/>.
 * Please send bug reports with examples or suggestions to
 * contact@beem-project.com or http://dev.beem-project.com/
 * Epitech, hereby disclaims all copyright interest in the program "Beem"
 * written by Frederic-Charles Barthelery,
 * Jean-Manuel Da Silva,
 * Nikita Kozlov,
 * Philippe Lago,
 * Jean Baptiste Vergely,
 * Vincent Veronis.
 * Nicolas Sadirac, November 26, 2009
 * President of Epitech.
 * Flavien Astraud, November 26, 2009
 * Head of the EIP Laboratory.
 */

package com.beem.project.beem.ui;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.IBinder;
import android.os.RemoteException;
import android.preference.PreferenceManager;
import android.provider.MediaStore;
import android.util.Log;
import android.view.ContextThemeWrapper;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ListAdapter;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.Toast;

import com.beem.project.beem.BeemService;
import com.beem.project.beem.BeemApplication;
import com.beem.project.beem.R;
import com.beem.project.beem.service.aidl.IXmppFacade;
import com.beem.project.beem.service.UserInfo;
import com.beem.project.beem.providers.AvatarProvider;
import com.beem.project.beem.utils.BeemBroadcastReceiver;
import com.beem.project.beem.utils.BeemConnectivity;
import com.beem.project.beem.utils.Status;

import java.io.File;
import java.util.Date;
import java.text.SimpleDateFormat;

/**
 * This Activity is used to change the status.
 *
 * @author nikita
 */
public class ChangeStatus extends Activity {

	private static final Intent SERVICE_INTENT = new Intent();
	static {
		SERVICE_INTENT.setComponent(new ComponentName("com.beem.project.beem", "com.beem.project.beem.BeemService"));
	}

	private static final String TAG = ChangeStatus.class.getSimpleName();
	private static final int AVAILABLE_FOR_CHAT_IDX = 0;
	private static final int AVAILABLE_IDX = 1;
	private static final int BUSY_IDX = 2;
	private static final int AWAY_IDX = 3;
	private static final int UNAVAILABLE_IDX = 4;
	private static final int DISCONNECTED_IDX = 5;

	private static final int ICON_SIZE = 80;

	private static final int SELECT_PHOTO_DLG = 0;

	private static final int CAMERA_WITH_DATA = 0;
	private static final int PHOTO_PICKED_WITH_DATA = 1;

	private static final File PHOTO_DIR = new File(Environment.getExternalStorageDirectory() + "/DCIM/Camera");

	private static final String KEY_CURRENT_PHOTO_FILE = "currentphotofile";

	private static final Uri MY_AVATAR_URI = Uri.parse(AvatarProvider.CONTENT_URI + "/my_avatar");

	private EditText mStatusMessageEditText;
	private Toast mToast;
	private Button mOk;
	private Button mClear;
	private Button mContact;
	private Spinner mSpinner;
	private ImageButton mAvatar;
	private Uri mAvatarUri;

	private SharedPreferences mSettings;
	private ArrayAdapter<CharSequence> mAdapter;
	private IXmppFacade mXmppFacade;
	private final ServiceConnection mServConn = new BeemServiceConnection();
	private final OnClickListener mOnClickOk = new MyOnClickListener();
	private final BeemBroadcastReceiver mReceiver = new BeemBroadcastReceiver();
	private boolean mShowCurrentAvatar = true;
	private boolean mDisableAvatar;
	private File mCurrentPhotoFile;

	/**
	 * Constructor.
	 */
	public ChangeStatus() {}

	/**
	 * {@inheritDoc}
	 */
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		Log.d(TAG, "oncreate");
		setContentView(R.layout.changestatus);

		mOk = (Button) findViewById(R.id.ChangeStatusOk);
		mOk.setOnClickListener(mOnClickOk);

		mClear = (Button) findViewById(R.id.ChangeStatusClear);
		mClear.setOnClickListener(mOnClickOk);

		mContact = (Button) findViewById(R.id.OpenContactList);
		mContact.setOnClickListener(mOnClickOk);

		BeemApplication app = (BeemApplication) getApplication();
		mAvatar = (ImageButton) findViewById(R.id.avatarButton);
		mAvatar.setOnClickListener(mOnClickOk);
		if (!app.isPepEnabled()) {
			View avatarPanel = findViewById(R.id.avatar_panel);
			avatarPanel.setVisibility(View.GONE);
		}

		mSettings = PreferenceManager.getDefaultSharedPreferences(this);
		mStatusMessageEditText = (EditText) findViewById(R.id.ChangeStatusMessage);
		mStatusMessageEditText.setText(mSettings.getString(BeemApplication.STATUS_TEXT_KEY, ""));

		mSpinner = (Spinner) findViewById(R.id.ChangeStatusSpinner);
		mAdapter = ArrayAdapter.createFromResource(this, R.array.status_types, android.R.layout.simple_spinner_item);
		mAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		mSpinner.setAdapter(mAdapter);

		mToast = Toast.makeText(this, R.string.ChangeStatusOk, Toast.LENGTH_LONG);
		mSpinner.setSelection(getPreferenceStatusIndex());

		this.registerReceiver(mReceiver, new IntentFilter(BeemBroadcastReceiver.BEEM_CONNECTION_CLOSED));
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	protected void onResume() {
		super.onResume();
		if (!BeemConnectivity.isConnected(getApplicationContext())) {
			Intent i = new Intent(this, Login.class);
			startActivity(i);
			finish();
		}
		bindService(new Intent(this, BeemService.class), mServConn, BIND_AUTO_CREATE);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	protected void onPause() {
		super.onPause();
		unbindService(mServConn);
	}

	/*
	 * (non-Javadoc)
	 * @see android.app.Activity#onDestroy()
	 */
	@Override
	protected void onDestroy() {
		super.onDestroy();
		this.unregisterReceiver(mReceiver);
	}

	/*
	 * The activity is often reclaimed by the system memory.
	 */
	@Override
	protected void onSaveInstanceState(Bundle outState) {
		if (mCurrentPhotoFile != null) {
			outState.putString(KEY_CURRENT_PHOTO_FILE, mCurrentPhotoFile.toString());
		}
		super.onSaveInstanceState(outState);
	}

	@Override
	protected void onRestoreInstanceState(Bundle savedInstanceState) {
		String fileName = savedInstanceState.getString(KEY_CURRENT_PHOTO_FILE);
		if (fileName != null) {
			mCurrentPhotoFile = new File(fileName);
		}
		super.onRestoreInstanceState(savedInstanceState);
	}

	@Override
	protected Dialog onCreateDialog(int id) {
		if (id == SELECT_PHOTO_DLG) return createPickPhotoDialog();
		return null;
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		// Ignore failed requests
		if (resultCode != RESULT_OK) return;

		switch (requestCode) {
		case PHOTO_PICKED_WITH_DATA:
			mAvatarUri = Uri.parse(data.getAction());
			Log.d(TAG, "selected avatar uri " + mAvatarUri);
			if (mAvatarUri != null) {
				mAvatar.setImageURI(mAvatarUri);
				mDisableAvatar = false;
				mShowCurrentAvatar = false;
			}
			break;

		case CAMERA_WITH_DATA:
			doCropPhoto(mCurrentPhotoFile);
			break;
		default:
			Log.w(TAG, "onActivityResult : invalid request code");

		}
	}

	/**
	 * Return the status index from status the settings.
	 *
	 * @return the status index from status the settings.
	 */
	private int getPreferenceStatusIndex() {
		return mSettings.getInt(BeemApplication.STATUS_KEY, AVAILABLE_IDX);
	}

	/**
	 * Return the status text from status the settings.
	 *
	 * @param id
	 *            status text id.
	 * @return the status text from status the settings.
	 */
	private String getPreferenceString(int id) {
		return mSettings.getString(getString(id), "");
	}

	/**
	 * convert status text to.
	 *
	 * @param item
	 *            selected item text.
	 * @return item position in the array.
	 */
	private int getStatusForService(String item) {
		int result;
		switch (mAdapter.getPosition(item)) {
		case ChangeStatus.DISCONNECTED_IDX:
			result = Status.CONTACT_STATUS_DISCONNECT;
			break;
		case ChangeStatus.AVAILABLE_FOR_CHAT_IDX:
			result = Status.CONTACT_STATUS_AVAILABLE_FOR_CHAT;
			break;
		case ChangeStatus.AVAILABLE_IDX:
			result = Status.CONTACT_STATUS_AVAILABLE;
			break;
		case ChangeStatus.AWAY_IDX:
			result = Status.CONTACT_STATUS_AWAY;
			break;
		case ChangeStatus.BUSY_IDX:
			result = Status.CONTACT_STATUS_BUSY;
			break;
		case ChangeStatus.UNAVAILABLE_IDX:
			result = Status.CONTACT_STATUS_UNAVAILABLE;
			break;
		default:
			result = Status.CONTACT_STATUS_AVAILABLE;
			break;
		}
		return result;
	}

	/**
	 * ClickListener for the avatarButton.
	 *
	 * @param button
	 *            the avatar button
	 */
	private void onAvatarButton(View button) {
		showDialog(SELECT_PHOTO_DLG);
	}

	/**
	 * Publish the selected avatar.
	 */
	private void publishAvatar() {
		try {
			if (mDisableAvatar) mXmppFacade.disableAvatarPublishing();
			else if (mAvatarUri != null) mXmppFacade.publishAvatar(mAvatarUri);
		} catch (RemoteException e) {
			Log.e(TAG, "Error while publishing avatar", e);
		}
	}

	/**
	 * Display the current avatar in the button.
	 */
	private void displayCurrentAvatar() {
		try {
			UserInfo ui = mXmppFacade.getUserInfo();
			if (ui == null) return;
			String avatarId = ui.getAvatarId();
			Log.d(TAG, "User info : avatar id " + avatarId);
			if (avatarId != null) {
				Uri uri = AvatarProvider.CONTENT_URI.buildUpon().appendPath(avatarId).build();
				mAvatar.setImageURI(uri);
			}
		} catch (RemoteException e) {
			Log.e(TAG, "Error while displaying current avatar", e);
		}
		mShowCurrentAvatar = false;
	}

	/*
	 * Some codes from AOSP (platform/packages/apps/Contacts)
	 * to select and crop an image.
	 */

	/**
	 * Creates a dialog offering two options: take a photo or pick a photo from the gallery.
	 *
	 * @return the dialog
	 */
	private Dialog createPickPhotoDialog() {
		// Wrap our context to inflate list items using correct theme
		final Context dialogContext = new ContextThemeWrapper(this, android.R.style.Theme_Light);

		final ListAdapter adapter = ArrayAdapter.createFromResource(dialogContext, R.array.pick_photo_items,
				android.R.layout.simple_list_item_1);

		final AlertDialog.Builder builder = new AlertDialog.Builder(dialogContext);
		builder.setTitle(R.string.select_avatar);
		builder.setSingleChoiceItems(adapter, -1, new DialogInterface.OnClickListener() {

			public void onClick(DialogInterface dialog, int which) {
				dialog.dismiss();
				switch (which) {
				case 0:
					doTakePhoto();
					break;
				case 1:
					doPickPhotoFromGallery();
					break;
				case 2:
					mDisableAvatar = true;
					mAvatar.setImageURI(null);
					break;
				default:
					Log.w(TAG, "DialogInterface onClick : invalid which code");
				}
			}
		});
		return builder.create();
	}

	/**
	 * Create a file name for the icon photo using current time.
	 *
	 * @return the filename
	 */
	private String getPhotoFileName() {
		Date date = new Date(System.currentTimeMillis());
		SimpleDateFormat dateFormat = new SimpleDateFormat("'IMG'_yyyyMMdd_HHmmss");
		return dateFormat.format(date) + ".jpg";
	}

	/**
	 * Launches Camera to take a picture and store it in a file.
	 */
	protected void doTakePhoto() {
		try {
			// Launch camera to take photo for selected contact
			PHOTO_DIR.mkdirs();
			mCurrentPhotoFile = new File(PHOTO_DIR, getPhotoFileName());
			final Intent intent = getTakePickIntent(mCurrentPhotoFile);
			startActivityForResult(intent, CAMERA_WITH_DATA);
		} catch (ActivityNotFoundException e) {
			Toast.makeText(this, R.string.photoPickerNotFoundText, Toast.LENGTH_LONG).show();
		}
	}

	/**
	 * Constructs an intent for capturing a photo and storing it in a temporary file.
	 *
	 * @param f
	 *            the temporary file to use to store the picture
	 * @return the intent
	 */
	public static Intent getTakePickIntent(File f) {
		Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE, null);
		intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
		return intent;
	}

	/**
	 * Sends a newly acquired photo to Gallery for cropping.
	 *
	 * @param f
	 *            the image file to crop
	 */
	protected void doCropPhoto(final File f) {
		try {

			// Add the image to the media store
			// level 8
			/*
			 * MediaScannerConnection.scanFile(
			 * this,
			 * new String[] { f.getAbsolutePath() },
			 * new String[] { null },
			 * null);
			 */

			// Launch gallery to crop the photo
			final Intent intent = getCropImageIntent(Uri.fromFile(f));
			startActivityForResult(intent, PHOTO_PICKED_WITH_DATA);
		} catch (ActivityNotFoundException e) {
			Log.e(TAG, "Cannot crop image", e);
			Toast.makeText(this, R.string.photoPickerNotFoundText, Toast.LENGTH_LONG).show();
		}
	}

	/**
	 * Constructs an intent for image cropping.
	 *
	 * @param photoUri
	 *            the uri of the photo to crop
	 * @return the intent
	 */
	public static Intent getCropImageIntent(Uri photoUri) {
		Intent intent = new Intent("com.android.camera.action.CROP");
		intent.setDataAndType(photoUri, "image/*");
		intent.putExtra("crop", "true");
		intent.putExtra("aspectX", 1);
		intent.putExtra("aspectY", 1);
		intent.putExtra("outputX", ICON_SIZE);
		intent.putExtra("outputY", ICON_SIZE);
		intent.putExtra(MediaStore.EXTRA_OUTPUT, MY_AVATAR_URI);
		return intent;
	}

	/**
	 * Launches Gallery to pick a photo.
	 */
	protected void doPickPhotoFromGallery() {
		try {
			// Launch picker to choose photo for selected contact
			final Intent intent = getPhotoPickIntent();
			startActivityForResult(intent, PHOTO_PICKED_WITH_DATA);
		} catch (ActivityNotFoundException e) {
			Toast.makeText(this, R.string.photoPickerNotFoundText, Toast.LENGTH_LONG).show();
		}
	}

	/**
	 * Constructs an intent for picking a photo from Gallery, cropping it and returning the bitmap.
	 *
	 * @return the intent
	 */
	public static Intent getPhotoPickIntent() {
		Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
		intent.setType("image/*");
		intent.putExtra("crop", "true");
		intent.putExtra("aspectX", 1);
		intent.putExtra("aspectY", 1);
		intent.putExtra("outputX", ICON_SIZE);
		intent.putExtra("outputY", ICON_SIZE);
		intent.putExtra(MediaStore.EXTRA_OUTPUT, MY_AVATAR_URI);
		// use this to get the bitmap in the intent
		// intent.putExtra("return-data", true);
		return intent;
	}

	/**
	 * connection to service.
	 *
	 * @author nikita
	 */
	private class BeemServiceConnection implements ServiceConnection {

		/**
		 * constructor.
		 */
		public BeemServiceConnection() {}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			mXmppFacade = IXmppFacade.Stub.asInterface(service);
			if (mShowCurrentAvatar) displayCurrentAvatar();
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public void onServiceDisconnected(ComponentName name) {
			mXmppFacade = null;
		}
	}

	/**
	 * User have clicked on ok.
	 *
	 * @author nikita
	 */
	private class MyOnClickListener implements OnClickListener {

		/**
		 * constructor.
		 */
		public MyOnClickListener() {}

		@Override
		public void onClick(View v) {
			if (v == mOk) {
				String msg = mStatusMessageEditText.getText().toString();
				int status = getStatusForService((String) mSpinner.getSelectedItem());
				Editor edit = mSettings.edit();
				edit.putString(BeemApplication.STATUS_TEXT_KEY, msg);
				if (status == Status.CONTACT_STATUS_DISCONNECT) {
					stopService(new Intent(ChangeStatus.this, BeemService.class));
				} else {
					try {
						mXmppFacade.changeStatus(status, msg.toString());
						edit.putInt(BeemApplication.STATUS_KEY, mSpinner.getSelectedItemPosition());
						publishAvatar();
					} catch (RemoteException e) {
						e.printStackTrace();
					}
					mToast.show();
				}
				edit.commit();
				ChangeStatus.this.finish();

			} else if (v == mClear) {
				mStatusMessageEditText.setText(null);
			} else if (v == mContact) {
				startActivity(new Intent(ChangeStatus.this, ContactList.class));
				ChangeStatus.this.finish();
			} else if (v == mAvatar) onAvatarButton(v);
		}
	}
}
